/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   gbx-emu - cpu.h                                                       *
 *   gbx-emu homepage: http://code.google.com/p/gbx-emu/                   *
 *   Copyright (C) 2009 olejl77@gmail.com                                  *
 *                                                                         *
 *   This program is free software: you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation, either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef CPU_H
#define CPU_H

class Gameboy;
class Memory;
class Debugger;
class Screen;
class Log;
class Cpu : public Common
{
friend class DebuggerWidget;
friend class Memory;
friend class Gameboy;
private:
    Gameboy *_gb;
    Memory *_mem;
    Screen *_scr;
    Debugger *_dbg;
    Log *_log;
    bool _debuggerEnabled;

public:
    Cpu(Gameboy *ptr);
    ~Cpu();

    void resetCpu();
    void Execute();
    void keyReleased(u8 key);
    void keyPressed(u8 key);

    void enableDebugger(bool enabled) { _debuggerEnabled = enabled; }

    const u8 *getA()   const { return &_A;    }
    const u8 *getIME() const { return &_IME;  }
    const u8 *getZ()   const { return &_Z;    }
    const u8 *getN()   const { return &_N;    }
    const u8 *getH()   const { return &_H;    }
    const u8 *getC()   const { return &_C;    }
    const u16 *getSP() const { return &m_SP;   }
    const u16 *getPC() const { return &_PC;   }
    const u16 *getBC() const { return &_BC.w; }
    const u16 *getDE() const { return &_DE.w; }
    const u16 *getHL() const { return &_HL.w; }

    u8 getButtons() const { return _joypad; }
    u8 getDirections() const { return (_joypad >> 4);  }

    void setMemory(Memory *ptr) { _mem = ptr; }
    void setScreen(Screen *ptr) { _scr = ptr; }
    void setDebugger(Debugger *ptr) { _dbg = ptr; }
    void setLog(Log *ptr) { _log = ptr; }

private:
    // special registers
    u8 _A;
    u8 _IME;
    u8 _Z;
    u8 _N;
    u8 _H;
    u8 _C;
    u16 m_SP;// Stack Pointer
	u16 _PC;// Program Counter
    reg _BC, _DE, _HL;

    bool m_halted;
    bool m_skip;

    // internal variables
    s32 _cycles;         // counts the cycles for updating display, timers etc.
    s32 _newLine;        // counts down from 456 to 0 and sets LCD modes
    u32 _timerCounter;   // counts cycles. Used for setting the timer interrupt
    u32 _divCounter;     // counts cycles. DIV io register is incremented every 256 cycles

    u8 *_c;              // table with cycles used for normal opcodes
    u8 *_c2;             // table with cycles used for 0xcb opcodes

    u8 _joypad;

    // debugging / profiling
    u32 *_opcode_cnt;
    u32 *_opcode_cnt_2;

    // Cpu Helper Functions
    void Reset();
    void executeOp(u8 opcode);      // Normal opcodes
    void executeOp_cb(u8 opcode);   // Opcodes starting with 0xcb
    void updateTimer(u8 cycle);
    void updateGraphic(u8 cycle);
    void serviceInterrupts();
    void setInterrupt(u8 bit);
    void checkLyc();

    // Opcode functions
    // 8-bit loads;
    void LD_nn_n(u8 *nn);
    void LD_r1_r2(u8 *r1, u8 r2);
    void LD_HL_r2(u8 r2);
    void LD_A_n(u8 n);
    void LD_n_A(u8 *n);
    void LD_nn_A(u16 nn);
    void LD_A_C();
    void LD_C_A();
    void LDD_A_HL();
    void LDD_HL_A();
    void LDI_A_HL();
    void LDI_HL_A();
    void LDH_n_A();
    void LDH_A_n();

    // 16-Bit Loads
    void LD_n_nn(u16 *n);
    void LD_SP_HL();
    void LDHL_SP_n();
    void LD_nn_SP();
    void PUSH_nn(u16 nn);
    void POP_nn(u16 *nn);

    //8-Bit ALU
    void ADD_A_n(u8 n);
    void ADC_A_n(u8 n);
    void SUB_n(u8 n);
    void SBC_A_n(u8 n);
    void AND_n(u8 n);
    void OR_n(u8 n);
    void XOR_n(u8 n);
    void CP_n(u8 n);
    void INC_n(u8 *n);
    void DEC_n(u8 *n);

    // 16-Bit Arithmetic
    void ADD_HL_n(u16 *n);
    void ADD_SP_n();
    void INC_nn(u16 *nn);
    void DEC_nn(u16 *nn);

    // Miscellaneous
    void SWAP_n(u8 *n);
    void DAA();
    void CPL();
    void CCF();
    void SCF();
    void NOP();
    void HALT();
    void STOP();
    void DI();
    void EI();

    // Rotates & Shifts
    void RLCA();
    void RLA();
    void RRCA();
    void RRA();
    void RLC_n(u8 *n);
    void RL_n(u8 *n);
    void RRC_n(u8 *n);
    void RR_n(u8 *n);
    void SLA_n(u8 *n);
    void SRA_n(u8 *n);
    void SRL_n(u8 *n);

    // Bit Opcodes
    void BIT_b_r(u8 b, u8 r);
    void SET_b_r(u8 b, u8 *r);
    void RES_b_r(u8 b, u8 *r);
    // Jumps
    void JP_nn();
    void JP_cc_nn(u8 flag, u8 test);
    void JP_HL();
    void JR_n();
    void JR_cc_n(u8 flag, u8 test);

    // Calls
    void CALL_nn();
    void CALL_cc_nn(u8 flag, u8 test);

    // Restarts
    void RST_n(u16 addr);

    // Returns
    void RET();
    void RET_cc(u8 flag, u8 test);
    void RETI();
};

enum { V_BLANK = 0, LCD_STAT, TIMER, SERIAL, JOYPAD };
enum {
    GB_CYCLES = 4194304,
    MAXCYCLES = 70224,
    LCD_MODE_CYCLES = 456,
    LCD_MODE2_CYCLES = LCD_MODE_CYCLES - 80,
    LCD_MODE3_CYCLES = LCD_MODE2_CYCLES - 172,
    LCD_MODE0_CYCLES = LCD_MODE3_CYCLES - 204,
    };

// Initialize the interrupt addresses
const u16 c_interruptAddr[] = { 0x0040, 0x0048, 0x0050, 0x0058, 0x0060 };

// Initialize clock select table
// 00:   4096 Hz    (~4194 Hz SGB)
// 01: 262144 Hz  (~268400 Hz SGB)
// 10:  65536 Hz   (~67110 Hz SGB)
// 11:  16384 Hz   (~16780 Hz SGB)
const u32 c_clockSel[] = { GB_CYCLES / 4096, GB_CYCLES / 262144, GB_CYCLES / 65536, GB_CYCLES / 16384 };

#endif // CPU_H
